#include "catalog.h"
#include "query.h"
#include "index.h"
#include "utility.h"
#include <string.h>
#include<stdlib.h>

// A simple scan select using a heap file scan
Status Operators::ScanSelect(const string & result,      // name of the output relation
	                     const int projCnt,          // number of attributes in the projection
                             const AttrDesc projNames[], // The projection list (as AttrDesc)
                             const AttrDesc *attrDesc,   // the attribute in the selection predicate
                             const Operator op,          // the predicate operation
                             const void *attrValue,      // a pointer to the literal value in the predicate
                             const int reclen)           // length of a tuple in the result relation
{
    cout << "Algorithm: File Scan" << endl;
    
    Status status;
    RID nextRid;
    RID newRid;
    AttrDesc * relattrs;
    int aCount;
    Record record;
    Record resultRec;
    resultRec.length = reclen;
         
	 
    HeapFileScan * scan;    
    HeapFile heapFile(result, status);

    if(status != OK)
    {
        return status;
    }
    
    //Get information about the relation and start the scan
    if(attrDesc)
    {
        status = attrCat->getRelInfo(string(attrDesc->relName), aCount, relattrs);
        
        if(status != OK)
        {
            delete[] relattrs;
            return status;
        }
        
        
        scan = new HeapFileScan(string(attrDesc->relName), attrDesc->attrOffset, attrDesc->attrLen,
        			       (Datatype)attrDesc->attrType, (char *)attrValue, op, status);

        if(status != OK)
        {
            if(scan)
	    	delete scan;
	    delete[] relattrs;
            return status;
        }
    }
    else
    {
        status = attrCat->getRelInfo(string(projNames[0].relName), aCount, relattrs);
         
	if(status != OK)
        {
            delete[] relattrs;
            return status;
        }

	scan = new HeapFileScan(string(projNames[0].relName), status);
        
	if(status != OK)
        {
            if(scan)
	    	delete scan;
	    delete[] relattrs;
            return status;
        } 
    }
 
    status = scan->scanNext(nextRid, record);
         
    if(status != OK)
    {
	delete[] relattrs;
	delete scan;
        return status;
    }            
    
    //Go through the heapfile on the relation
    while(status == OK)
    {
        //Allocate memory for the new tuple
	resultRec.data = malloc(record.length);
      
        if(!resultRec.data)
        {
	    delete[] relattrs;
	    delete scan;
            return INSUFMEM;
        }

        //Loop through projection list and add attributes to new tuple
	for(int i = 0; i < projCnt; i++)
	{
            for(int j = 0; j < aCount; j++)
	    {
	        if(strcmp(projNames[i].relName, relattrs[j].relName) == 0 && 
	           strcmp(projNames[i].attrName, relattrs[j].attrName) == 0)
	        {
	            if(projNames[i].attrType != relattrs[j].attrType)
	            {
		    	free(resultRec.data);
	                delete[] relattrs;
	                delete scan;
			return ATTRTYPEMISMATCH;
	            }
	 
	            memcpy(((char *)resultRec.data)+projNames[i].attrOffset, 
		         ((char *)record.data)+relattrs[j].attrOffset, projNames[i].attrLen);
	            break;
		}
	    }
	}  

	//Add the newly formed tuple to the result heapfile
        status = heapFile.insertRecord(resultRec, newRid);
	
	
	status = scan->scanNext(nextRid, record);
    }
  
    delete relattrs;
    delete scan;
    
    if(status != FILEEOF)
    {
	return status;
    }

  return OK;
}
























